/**
 * 
 */
package neptune.web.client.view.components.editor;

import java.util.ArrayList;

import neptune.web.client.model.topology.SerializableIPAddress;
import neptune.web.client.model.topology.SerializableLink;
import neptune.web.client.model.topology.SerializableNetworkInterface;
import neptune.web.client.model.topology.SerializableNode;
import neptune.web.client.model.topology.SerializableProperty;
import neptune.web.client.model.topology.SerializableSoftware;
import neptune.web.client.model.topology.SerializableTopology;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeImages;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * @author Roberto Bifulco [RobertoBifulco.it] [info@robertoBifulco.it]
 * 
 */
public class TopologyEditor extends Composite {

	private SerializableTopology topology;

	private Tree topologyTree;

	private GraphicPanel graphPanel;

	public TopologyEditor() {
		VerticalPanel mainPanel = new VerticalPanel();
		initWidget(mainPanel);

		mainPanel.setSize("100%", "100%");

		HorizontalPanel splitPanel = new HorizontalPanel();
		splitPanel.setSize("100%", "100%");

		mainPanel.add(splitPanel);
		mainPanel.setCellWidth(splitPanel, "100%");

		Panel treePanel = buildTreePanel();
		splitPanel.add(treePanel);
		ScrollPanel graphPanelWrap = new ScrollPanel();
		graphPanelWrap.setSize("100%", "500px");
		graphPanel = buildGraphPanel();
		graphPanelWrap.setWidget(graphPanel);
		splitPanel.add(graphPanelWrap);

		splitPanel.setCellWidth(treePanel, "25%");
		splitPanel.setCellWidth(graphPanel, "75%");

		// Styles
		mainPanel.setStylePrimaryName("TopologyEditor");
		splitPanel.setStylePrimaryName("TopologyEditor-splitPanel");
		graphPanelWrap.setStylePrimaryName("TopologyEditor-graphPanelWrap");
	}

	private GraphicPanel buildGraphPanel() {
		GraphicPanel panel = new GraphicPanel(1200, 500, true);
		return panel;
	}

	private Panel buildTreePanel() {
		ScrollPanel panel = new ScrollPanel();
		panel.setHeight("500px");
		panel.setWidth("100%");

		topologyTree = new Tree((TreeImages) GWT.create(TreeImagesIEFix.class));
		topologyTree.setAnimationEnabled(true);
		updateTopologyTree();

		panel.setWidget(topologyTree);

		panel.setStylePrimaryName("TopologyEditor-treePanel");
		topologyTree.setStylePrimaryName("TopologyEditor-tree");

		return panel;
	}

	public void updateTopologyTree() {
		TreeItem root = new TreeItem(new Label("Topology"));
		TreeItem nodes = new TreeItem();
		TreeItem links = new TreeItem();

		if (topology == null)
			topology = new SerializableTopology();

		root.addItem(nodes);
		nodes.setWidget(new NodesMenuBar(topology, nodes, this));
		root.addItem(links);
		links.setWidget(new LinksMenuBar(topology, links, this));
		topologyTree.removeItems();
		topologyTree.addItem(root);
		root.setState(true);

		// NODES
		for (SerializableNode serializableNode : topology.getNodes()) {
			TreeItem nodeItem = new TreeItem();
			nodes.addItem(nodeItem);

			MenuBar label = new NodeMenuBar(serializableNode, topology,
					nodeItem, this);
			nodeItem.setWidget(label);

			TreeItem interfacesItem = new TreeItem();
			MenuBar interfacesLabel = new InterfacesMenuBar(serializableNode,
					topology, interfacesItem);
			interfacesItem.setWidget(interfacesLabel);
			nodeItem.addItem(interfacesItem);

			for (SerializableNetworkInterface serInterface : serializableNode
					.getInterfaces()) {

				TreeItem interfaceItem = new TreeItem();
				interfacesItem.addItem(interfaceItem);

				NetworkIFMenuBar interfaceLabel;
				// Cambia il menu a seconda che l'interfaccia sia o meno di
				// controllo
				if (serInterface.getInterfaceName().equals("eth0"))
					interfaceLabel = new ControlNetIFMenuBar(serInterface,
							serializableNode, topology, interfaceItem);
				else
					interfaceLabel = new NetworkIFMenuBar(serInterface,
							serializableNode, topology, interfaceItem);

				interfaceItem.setWidget(interfaceLabel);

				for (SerializableIPAddress serializableIPAddress : serInterface
						.getIpAddresses()) {

					TreeItem ipItem = new TreeItem();
					interfaceItem.addItem(ipItem);

					IpAddressMenuBar ipLabel = new IpAddressMenuBar(
							serializableIPAddress, serInterface, ipItem);
					ipItem.setWidget(ipLabel);
				}
			}

			TreeItem softwaresItem = new TreeItem();
			MenuBar softwaresLabel = new SoftwaresMenuBar(serializableNode,
					softwaresItem);
			softwaresItem.setWidget(softwaresLabel);
			nodeItem.addItem(softwaresItem);

			for (SerializableSoftware serializableSoftware : serializableNode
					.getInstalledSoftwares()) {

				TreeItem softwareItem = new TreeItem();
				softwaresItem.addItem(softwareItem);

				SoftwareMenuBar softwareLabel = new SoftwareMenuBar(
						serializableSoftware, serializableNode, softwareItem);
				softwareItem.setWidget(softwareLabel);
			}
		}

		// LINKS
		for (SerializableLink serializableLink : topology.getLinks()) {

			TreeItem linkItem = new TreeItem();
			links.addItem(linkItem);

			LinkMenuBar linkLabel = new LinkMenuBar(serializableLink, topology,
					linkItem, this);
			linkItem.setWidget(linkLabel);

			for (SerializableProperty serializableProperty : serializableLink
					.getProperties()) {

				TreeItem propItem = new TreeItem();
				linkItem.addItem(propItem);

				Label propLabel = new Label(serializableProperty.getName()
						+ "=" + serializableProperty.getValue());
				propItem.setWidget(propLabel);
			}
		}
	}

	/**
	 * @return the topology
	 */
	public SerializableTopology getTopology() {
		return topology;
	}

	/**
	 * @param topology
	 *            the topology to set
	 */
	public void setTopology(SerializableTopology topology) {
		this.topology = topology;
		updateTopologyTree();
		drawGraphics();
	}

	public void drawGraphics() {
		graphPanel.clearPaints();
		Label[] nodeGraphics = new Label[topology.getNodes().size()];
		for (int i = 0; i < nodeGraphics.length; i++) {
			nodeGraphics[i] = createNodeGraphic(topology.getNodes().get(i));
		}

		int x = 60, y = 60;
		for (int i = 0; i < nodeGraphics.length; i++) {
			graphPanel.add(nodeGraphics[i], x, y);
			x = x + 100;
			if (x > graphPanel.getOffsetWidth()) {
				x = x - graphPanel.getOffsetWidth();
				y = y + 100;
			}
			graphPanel.makeDraggable(nodeGraphics[i]);
		}

		ArrayList<SerializableLink> links = topology.getLinks();
		for (SerializableLink serializableLink : links) {
			Widget w1 = null, w2 = null;
			for (int i = 0; i < nodeGraphics.length; i++) {
				if (nodeGraphics[i].getText().equals(
						serializableLink.getSource().getNodeId()))
					w1 = nodeGraphics[i];
				else if (nodeGraphics[i].getText().equals(
						serializableLink.getDestination().getNodeId()))
					w2 = nodeGraphics[i];
			}
			if (w1 != null && w2 != null) {
				graphPanel.addConnection(w1, w2);
			}
		}

		graphPanel.redrawDraggable();
	}

	public void updateGraphics() {
		graphPanel.redrawDraggable();
	}

	public Label createNodeGraphic(SerializableNode node) {
		Label graph = new Label(node.getId());
		graph.setStylePrimaryName("TopologyEditor-nodeGraphic");
		return graph;
	}

	/**
	 * @return the graphPanel
	 */
	public GraphicPanel getGraphPanel() {
		return graphPanel;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.gwt.user.client.ui.UIObject#setVisible(boolean)
	 */
	@Override
	public void setVisible(boolean visible) {
		super.setVisible(visible);
		if (visible)
			graphPanel.redrawDraggable();
	}

	public void reset() {
		topology = null;
		graphPanel.clearPaints();
		graphPanel.removeAllConnections();
		updateTopologyTree();
		updateGraphics();
	}
}
